<template>
  <div class="overflow-auto flex flex-col items-center">
    <img
      v-if="isMobileTerminal"
      src="@/assets/style/svg/close.svg"
      class="w-[.3rem] h-[.3rem] p-[.05rem] m-[.1rem] ml-auto"
      fillClass="fill-zinc-900 dark:fill-zinc-200 "
      @click="close"
    />

    <img class="" ref="imageTarget" :src="blob" />

    <m-button class="mt-[.4rem] w-[80%] xl:w-1/2" @click="onConfirmClick"
      >确定</m-button
    >
  </div>
</template>

<script>
const EMITS_CLOSE = 'close'
</script>

<script setup>
import { ref, onMounted, onUpdated } from 'vue'
import { useUserStore } from '@/store/user'
import { isMobileTerminal } from '@/utils/flexible'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { getOSSClient } from '@/utils/sts'
import { message } from '@/libs'
import { putProfile } from '@/server/api/sys'

defineProps({
  blob: {
    type: String,
    required: true
  }
})

const emits = defineEmits([EMITS_CLOSE])
const userStore = useUserStore()

// 移动端配置对象
const mobileOptions = {
  // 将裁剪框限制在画布的大小
  viewMode: 1,
  // 移动画布，裁剪框不动
  dragMode: 'move',
  // 裁剪框固定纵横比：1:1
  aspectRatio: 1,
  // 裁剪框不可移动
  cropBoxMovable: false,
  // 不可调整裁剪框大小
  cropBoxResizable: false
}

// PC 端配置对象
const pcOptions = {
  // 裁剪框固定纵横比：1:1
  aspectRatio: 1,
  // 将裁剪框限制在画布的大小
  viewMode: 1
}

/**
 * 图片裁剪处理
 */
const imageTarget = ref(null)
let cropper = null
onMounted(() => {
  /**
   * 接收两个参数：
   * 1. 需要裁剪的图片 DOM
   * 2. options 配置对象
   */
  cropper = new Cropper(
    imageTarget.value,
    isMobileTerminal.value ? mobileOptions : pcOptions
  )
})

onUpdated(() => {
  createCropper()
})

/**
 * 确定按钮点击事件
 */
const onConfirmClick = () => {
  cropper.getCroppedCanvas().toBlob((blob) => {
    putObjectToOSS(blob)
  })
}

/**
 * 关闭事件
 */
const close = () => {
  emits(EMITS_CLOSE)
}

const createCropper = () => {
  if (!imageTarget.value) {
    return
  }

  if (cropper) {
    cropper.destroy()
  }

  cropper = new Cropper(
    imageTarget.value,
    isMobileTerminal.value ? mobileOptions : pcOptions
  )
}

/**
 * 进行 OSS 上传
 */
let ossClient = null
const putObjectToOSS = async (file) => {
  if (!ossClient) {
    ossClient = await getOSSClient()
  }
  try {
    // 因为当前凭证只具备 images 文件夹下的访问权限，所以图片需要上传到 images/xxx.xx 。否则你将得到一个 《AccessDeniedError: You have no right to access this object because of bucket acl.》 的错误
    const fileTypeArr = file.type.split('/')
    const fileName = `${userStore.userInfo.username}/${Date.now()}.${
      fileTypeArr[fileTypeArr.length - 1]
    }`
    // 文件存放路径，文件
    const res = await ossClient.put(`images/${fileName}`, file)
    // 上传到服务器
    onChangeProfile(res.url)
  } catch (e) {
    message('error', e)
  }
}

/**
 * 上传新头像到服务器
 */
const onChangeProfile = async (avatar) => {
  // 更新本地数据
  userStore.userInfo = {
    ...userStore.userInfo,
    avatar
  }
  // 更新服务器数据
  await putProfile(userStore.userInfo)
  // 通知用户
  message('success', '用户头像修改成功')
  // 关闭 dialog
  close()
}
</script>
